#include <iostream>
#include <cstdlib>
#include <vector>
#include <cassert>
#include <ctime>

using namespace std;
//*********************************************************************************
//  class Board encapsulates a 2 dimensional grid of characters.
//    
//    Each position on the board contains a single character and is referenced with 
//    an X,Y reference where X refers to the row number and Y refers to the column number. 
//
//    When displayed or output, the board is setup like an Excel spreadsheet, not like 
//    a standard Cartiesian coordinate system; visually, X=0, Y=0 refers to the upper 
//    left corner of the board (not the center of the board).
//
//    To declare a Board object, you MUST use the constructor that takes height, width
//    and a default background character. E.g.:
//      
//         Board GameBoard(20,30,' ') ;
//
//    creates a Board object names GameBoard that has 20 rows, and 30 columns, and
//    uses the space character as its background.
//
//    The background character determines what an "empty" position is. In the example
//    above if an X,Y position contains a ' ', then the space is empty. Anyother 
//    character means the space is occupied. 
//
//**********************************************************************************

class Board
{
public:

  // output the board
  friend ostream& operator << ( ostream& out, Board& B) ;

  Board () {} ; // Does nothing. Don't declare a board object without invoking 
                //  the constructor below instead.

  // initializes an empty board of height times width
  //  all positions are filled with character backgroundCh.
  Board (int height, int width, char backgroundCh);

  char  get(int X, int Y) ;          // get the character in position X,Y
  void  put(char ch, int X, int Y) ; // places ch in position X,Y
  void  del(int X, int Y) ;          // delete the character in position X,Y

  char  getBackgroundCh();           // returns the default background character

  bool  isEmpty (int X, int Y);      // returns true if position X,Y is empty
                                     //   (that is it contains a character that is equal 
                                     //   to the default background char)

  bool  isOccupied (int X, int Y);   // returns true if position X,Y is NOT empty
                                     //   (that is it contains a character that is equal 
                                     //   to something OTHER than the default background char
                                     // Note: if X,Y is off the board, isOccupied returns false 


  void  fillBoard(char ch) ; // fill all positions on the board with char ch.
                             //   Ignores the default background char.

  void  clearBoard() ;       // clears the board (overwrites all the cells
                             //   with the default background character).



private:


  int  mWidth;
  int  mHeight;
  char mBackgroundCh ;
  vector< vector <char> > mGrid ;

  // Assert a valid position on the board, if X,Y is 
  //  not valid, then abort program.
  void posAssert(int X, int Y);

  // Returns true if X,Y is a valid posistion on the board, false
  //   otherwise
  bool  isOnGrid(int X, int Y);  // used with isOccupied


};

//////////////////////////////
//****************************
// Global functions -- outside of the board class.
//   can be called without using the dot operator.
//
// funtion wait will pause the CPU a certain number
// of seconds at runtime.
  
void wait ( int seconds );


//***************************
/////////////////////////////




void Board::posAssert(int X, int Y)
{
  if (X<0 || X>=mHeight || Y<0 || Y >= mWidth)
  {
       cout << "Error. Off of board. Aborting. ";
       system("pause");
       exit(1);
  }
}
char Board::get (int X, int Y)
{
  posAssert(X,Y);
  return mGrid[X][Y];
}
void Board::put (char ch, int X, int Y)
{
      posAssert(X,Y);
      mGrid[X][Y] = ch ;
}
void  Board::del(int X, int Y)
{
     posAssert(X,Y);
     mGrid[X][Y] = mBackgroundCh ;
}
char  Board::getBackgroundCh()
{
      return mBackgroundCh ;
}
bool  Board::isOccupied (int X, int Y)
{
     if (isOnGrid(X,Y))
     {
     return (mGrid[X][Y]!=mBackgroundCh)?true:false;
     }
     else     
     {
        return false;     
     }     
}

bool  Board::isEmpty (int X, int Y)
{
      return  !isOccupied(X,Y);
}

bool Board::isOnGrid(int X, int Y)
{
  if (X<0 || X>=mHeight || Y<0 || Y >= mWidth)
  {
    return false; 
  }  
  else
  { 
    return true;  
  }
}
void  Board::clearBoard()
{

  fillBoard (mBackgroundCh);
}

Board :: Board (int height, int width, char ch )
{

   mHeight = height; mWidth = width; mBackgroundCh=ch ;

   // create a row
   vector <char> aRow;
   for (int j=0; j<width; j++)
   {
     aRow.push_back(mBackgroundCh);
   }

   for (int i=0; i<height; i++)
   {
      mGrid.push_back(aRow);
   }


}
void Board :: fillBoard (char ch)
{
   for (int i=0; i<mHeight; i++)
   {
     for (int j=0; j<mWidth; j++)
     {
        mGrid[i][j] = ch;
     }
   }
}
ostream& operator << ( ostream& out, Board& B)
{
   for (int i=0; i<B.mHeight; i++)
   {
     cout << "|" ;
     for (int j=0; j<B.mWidth; j++)
     {
        out << B.mGrid[i][j];
     }
     cout <<"|" ;
     out << endl;
   }
   return out;
}

/////////////////////////////////
/////GLOBAL NON-Class functions
/////////////////////////////////
void wait ( int seconds )
{
   clock_t endwait;
   endwait = clock () + seconds * CLOCKS_PER_SEC ;
   while (clock() < endwait) {}
}




